local famBags = LibStub('AceAddon-3.0'):GetAddon('famBags')
famBags.Sections = {
   bags = {},
   bank = {}
}
famBags.Sections.Bin = {
   bags = {},
   bank = {}
}
-- :::::::::::: LOCALS ::::::::::::: -------------------------------------------------------------------------

-- :::::::::::: famBags.Sections ::::::::::::: -------------------------------------------------------------------------
function famBags.Sections:Create(sectionType, bag, index, title)
   local db = famBags.db.profile
   self[bag][sectionType] = self[bag][sectionType] or {}

   if not self[bag][sectionType][index] then
      local sectionIndex = (sectionType == 'bags') and 'bags' or index
      db.sections[sectionIndex] = db.sections[sectionIndex] or {}
      db.sections[sectionIndex].bg = db.sections[sectionIndex].bg or famBags:GetBGDefaults()
      db.sections[sectionIndex].title = db.sections[sectionIndex].title or famBags:GetTitleDefaults()

      local name = string.format('famBags_%s_%s_%s', bag, sectionType, index)
      if title then
         local minimg = famBags.db.profile.minimized_sections[bag][index] and 'plus' or 'minus'
         title = '|TInterface\\Addons\\famBags\\Textures\\'..minimg..'.blp:16:16:0:-1:64:64:1:64:1:64|t '..title
      end
      self[bag][sectionType][index] = famBags:CreateBagFrame(
         name,
         title, (bag == 'bags') and famBags.famBagsFrame or famBags.famBankFrame,
         5, 100, 100, db.sections[sectionIndex])
      local f = self[bag][sectionType][index]

      f.sectionType = sectionType
      f.name = index
      f.bag = bag

      f.highlight = f.highlight or CreateFrame('Frame', name..'_Highlight', f)
      f.highlight:SetFrameLevel(7)
      f.highlight:SetBackdrop( {
         bgFile = nil,
         edgeFile = "Interface\\Addons\\famBags\\Textures\\sectionborder.blp", tile = false, tileSize = 0, edgeSize = 10,
         insets = { left = -1, right = -1, top = -1, bottom = -1 }
      })
      f.highlight:SetAllPoints(f)
      f.highlight:Hide()

      f.titleFrame:EnableMouse(true)
      f.titleFrame:SetScript('OnEnter', function(f)
         local parent = f:GetParent()
         parent.highlight:Show()
         if ( MerchantFrame:IsShown() and MerchantFrame.selectedTab == 1 ) then
            ShowContainerSellCursor(parent:GetID(), 0)
         end
         if famBags.db.profile.layout.sections.tooltip then
            local x = parent:GetRight()
            GameTooltip:SetOwner(parent, (x >= ( GetScreenWidth() / 2)) and "ANCHOR_LEFT" or "ANCHOR_RIGHT")
            GameTooltip:AddLine('|cffc5affe'..famBags.L['Categories']..':|r '..parent.name, 1, 1, 1)
            if famBags.db.profile.layout.sections.tooltip_vendor then
               local total = 0
               for _,b in ipairs(famBags.Buttons.Current[parent.bag][parent.name]) do
                  total = total + ((b.info.sellPrice or 0) * (b.info.count or 0))
                  if b.stacks and #b.stacks > 0 then
                     for _,b1 in ipairs(b.stacks) do
                        total = total + ((b1.info.sellPrice or 0) * (b1.info.count or 0))
                     end
                  end
               end
               local t = '--'
               if total > 0 then
                  local g, s, c = total / 100 / 100, (total / 100) % 100, total % 100
                  t = ((g >= 1) and string.format('%d|TInterface\\MoneyFrame\\UI-GoldIcon:16:16:3:0:64:64:4:60:4:60|t ', g) or '')..
                      ((s >= 1) and string.format(' %d|TInterface\\MoneyFrame\\UI-SilverIcon:16:16:3:0:64:64:4:60:4:60|t ', s) or '')..
                      string.format(' %d|TInterface\\MoneyFrame\\UI-CopperIcon:16:16:3:0:64:64:4:60:4:60|t ', c)
               end
               GameTooltip:AddLine('|cfff3cc20'..famBags.L['Vendor Value']..':|r '..t, 1, 1, 1)
            end
            GameTooltip:Show()
         end
      end)
      f.titleFrame:SetScript('OnLeave', function(f)
         f:GetParent().highlight:Hide()
         ResetCursor()
         if famBags.db.profile.layout.sections.tooltip then
            GameTooltip:Hide()
         end
      end)
      f.titleFrame:SetScript('OnMouseUp', function(f, button)
         local section = f:GetParent()
         if button == 'RightButton' then
            if famBags.MAINFRAMES[section.bag].offline then return end
            famBags.SellingSectionBag = section.bag
            famBags.SellingSection = section.name
            if MerchantFrame:IsShown() and MerchantFrame.selectedTab ~= 2 then
               StaticPopup_Show("FAMBAGS_CONFIRMSECTIONSELL")
            elseif famBags.famBankFrame:IsVisible() then
               famBags:UseSectionItems()
            else
               famBags.SellingSectionBag = nil
               famBags.SellingSection = nil
            end
         elseif button == 'LeftButton' and famBags.db.profile.layout.general.sections == 'categories' then
            famBags.db.profile.minimized_sections[section.bag][section.name] = not famBags.db.profile.minimized_sections[section.bag][section.name]
            local t = f.titleText.text
            t = famBags.db.profile.minimized_sections[section.bag][section.name] and
               gsub(t, 'minus.blp.', 'plus.blp:', 1) or
               gsub(t, 'plus.blp.', 'minus.blp:', 1)
            famBags:SetTextLayout(f, f.titleText, famBags.db.profile.sections[section.name].title.text, t)
            famBags:LayoutBagsButtons(section.bag)
         end
      end)
   end

   return self[bag][sectionType][index]
end

function famBags.Sections:CreateEmpty(bag)
   local db = famBags.db.profile
   self[bag].empties = self[bag].empties or famBags:CreateBagFrame(
      string.format('famBagsEmptiesSection_%s', bag),
      nil, (bag == 'bags') and famBags.famBagsFrame or famBags.famBankFrame,
      5, 100, 100, db.layout.empties)
   return self[bag].empties
end

function famBags.Sections:Destroy(sectionType, index)
   for bag in pairs(famBags.BagIndexes) do
      if self[bag] and self[bag][sectionType] and self[bag][sectionType][index] then
         self[bag][sectionType][index]:Hide()
         self[bag][sectionType][index] = nil
      end
   end
end

function famBags.Sections:HideSectionsType(bag, sectionType)
   if self[bag][sectionType] then
      for _, bag in pairs(self[bag][sectionType]) do
         bag:Hide()
      end
   end
end

function famBags.Sections:HideSection(bag, sectionType, index, layoutBags)
   if self[bag][sectionType][index] then
      self[bag][sectionType][index]:Hide()
--[[      if layoutBags then
         self:LayoutBags(bag, sectionType)
      end]]
   end
end

function famBags.Sections:SetTitle(bag, section, title)
   local db = (bag == 'bags') and famBags.db.profile.sections.bags.title.text or famBags.db.profile.sections[section.name].title.text
   if section.name == BANK_CONTAINER then
      title = famBags.L['Bank Main Container']
   end
   famBags:SetTextLayout(section.titleFrame, 'titleText', db, title)
end

function famBags.Sections:BuildBagsSections(bag)
   for _, i in ipairs(famBags.BagIndexes[bag]) do
      local bagname = GetBagName(i)
      self:Create('bags', bag, i, bagname)
      if not bagname then
         self:HideSection(bag, 'bags', i)
      end
   end
end

function famBags.Sections:BuildCategoriesSections(bag)
   self[bag].categories = self[bag].categories or {}
   for _, cat in ipairs(famBags.SortedCategories[bag]) do
      if not self[bag].categories[cat] then
         self:Create('categories', bag, cat, cat)
      end
      self[bag].categories[cat]:Hide()
   end
end

function famBags.Sections:WipeBin(bag)
   for _, row in ipairs(self.Bin[bag]) do
      row.width = 0
      wipe(row.cells)
   end
end

function famBags.Sections:PushToBin(bag, section)
   local width = section:GetWidth()
   local db = famBags.db.profile
   local dbmin = db.minimized_sections
   local bw = (famBags.Buttons[0] and famBags.Buttons[0][1]) and famBags.Buttons[0][1]:GetWidth() or famBags.Buttons[BANK_CONTAINER][1]:GetWidth()
   local dbindex = (bag == 'bags') and 'mainwindow' or 'bank'
   local maxwidth = ((bw * db[dbindex].layout.buttons_x_row) + (db.layout.buttons.hspacing * (db[dbindex].layout.buttons_x_row - 1)) + (db.layout.buttons.hpadding * 2)) * db.layout.buttons.size
   local hs = db.layout.sections.hspacing
   local bestfit = nil
   for i, row in ipairs(self.Bin[bag]) do
      local cells = #row.cells
      if cells == 0 then
         if not bestfit then
            bestfit = row
         end
         break
      elseif (db.layout.sections.compact
              and ((dbmin[bag][section.name] and dbmin[bag][row.cells[cells].name]) or
                   (not dbmin[bag][section.name] and not dbmin[bag][row.cells[cells].name]))
              and row.width + hs + width <= maxwidth
              and ((not bestfit) or row.width > bestfit.width)) then
         bestfit = row
      end
   end
   if bestfit then
      bestfit.width = bestfit.width + hs + width
      bestfit.cells[#bestfit.cells + 1] = section
   else
      local i = #self.Bin[bag] + 1
      self.Bin[bag][i] = {}
      self.Bin[bag][i].width = width
      self.Bin[bag][i].cells = { section }
   end
end

function famBags.Sections:UpdateBin(bag, sectionType)
   local db = famBags.db.profile.minimized_sections
   self:WipeBin(bag)
   if sectionType == 'categories' then
      local minimized
      for k, section in ipairs(famBags.SortedCategories[bag]) do
         section = self[bag]['categories'][section]
         if section and section:IsVisible() then
            if not db[bag][section.name] then
               self:PushToBin(bag, section)
            else
               minimized = true
            end
         end
      end
      if minimized then
         for k, section in ipairs(famBags.SortedCategories[bag]) do
            section = self[bag]['categories'][section]
            if db[bag][section.name] then
               self:PushToBin(bag, section)
            end
         end
      end
   else
      local section
      for _, i in ipairs(famBags.BagIndexes[bag]) do
         section = self[bag]['bags'][i]
         if section:IsVisible() then
            self:PushToBin(bag, section)
         end
      end
   end
end

function famBags.Sections:LayoutBags(bag, sectionType, clear)
   if clear then
      if sectionType ~= 'bags' then
         self:HideSectionsType(bag, 'bags')
      end
      if sectionType ~= 'categories' then
         self:HideSectionsType(bag, 'categories')
      end
   end
   if self[bag][sectionType] then
      local frame = (bag == 'bags') and famBags.famBagsFrame or famBags.famBankFrame
      local dbbag = (bag == 'bags') and 'mainwindow' or 'bank'
      local db = famBags.db.profile.layout.sections
      local previous = frame.bodyFrame
      local th = frame.titleFrame:GetHeight()
      local h = db.vpadding + th
      local lw = 0
      local lh = 0
      local w = 0
      local y = 0
      local hsection
      local title_inset = famBags.db.profile[dbbag].title.is_inset
      if title_inset then
         y = th + (famBags.db.profile[dbbag].title.inset)
         h = h + (famBags.db.profile[dbbag].title.inset * 2)
      end
      if famBags.isStackMode then
         local dbe = famBags.db.profile.layout.empties
         local s = self[bag].empties
         s:ClearAllPoints()
         s:SetPoint(dbe.vpos..'LEFT', frame.bodyFrame, dbe.vpos..'LEFT', dbe.hpadding, (dbe.vpos == 'TOP') and -(y + dbe.vpadding) or dbe.vpadding)
         s:SetPoint('RIGHT', frame.bodyFrame, 'RIGHT', -dbe.hpadding, 0)
         if dbe.vpos == 'TOP' then
            y = y + s:GetHeight() + dbe.vpadding
         end
         s:Show()
      end
      y = -y - db.vpadding
      self:UpdateBin(bag, sectionType)
      local bin = self.Bin[bag]
      for i, row in ipairs(bin) do
         lw, lh = 0, 0
         if row.width == 0 then break end
         for j, section in pairs(row.cells) do
            section:ClearAllPoints()
            if j == 1 then
               if i == 1 then
                  section:SetPoint('TOPLEFT', frame.bodyFrame, 'TOPLEFT', db.hpadding, y)
               else
                  section:SetPoint('LEFT', bin[i-1].cells[1], 'LEFT', 0, 0)
                  section:SetPoint('TOP', hsection, 'BOTTOM', 0, -db.vspacing)
               end
               lh = section:GetHeight()
               hsection = section
            else
               section:SetPoint('TOPLEFT', previous, 'TOPRIGHT', db.hspacing, 0)
               lw = lw + db.hspacing
               local alh = section:GetHeight()
               if alh > lh then
                  lh = alh
                  hsection = section
               end
            end
            lw = lw + section:GetWidth()
            previous = section
            if famBags.db.profile.sections[section.name] then
               famBags:SetTextLayout(section.titleFrame, 'titleText', famBags.db.profile.sections[section.name].title.text, nil)
            end
         end
         h = h + db.vspacing + lh
         w = max(w, lw)
      end
      h = h - db.vspacing + db.vpadding
      if famBags.isStackMode then
         h = h + self[bag].empties:GetHeight() + db.vpadding
      end
      local dbw = famBags.db.profile[dbbag].layout
      local dbb = famBags.db.profile.layout.buttons
      if dbw.fixed_width then
         local bw = (famBags.Buttons[0] and famBags.Buttons[0][1]) and famBags.Buttons[0][1]:GetWidth() or 43
         w = ((db.hpadding * 2) + (dbb.hpadding * 2) + (dbb.hspacing * (dbw.buttons_x_row - 1)) + (bw * dbw.buttons_x_row)) * dbb.size
      else
         w = w + (db.hpadding * 2)
         if bag == 'bank' and famBags.db.profile.bankwindow.enabled and famBags.famBagsBlizzardBankFrame then
            local bbw = famBags.famBagsBlizzardBankFrame.PurchaseInfo:GetWidth()
            if w < bbw then
               w = bbw
            end
         end
      end
      frame:SetWidth((w > 250) and w or 250)
      frame:SetHeight(h)
      if bag == 'bags' then
         famBags:UpdateInputFrame(famBags.BagsSearchFrame, famBags.db.profile.mainwindow.search)
         if famBags.OFFLINE_ENABLED then
            famBags:UpdateInputFrame(famBags.BagsAltsFrame, famBags.db.profile.mainwindow.alts)
         end
      else
         famBags:UpdateInputFrame(famBags.BankSearchFrame, famBags.db.profile.bank.search)
         if famBags.OFFLINE_ENABLED then
            famBags:UpdateInputFrame(famBags.BankAltsFrame, famBags.db.profile.bank.alts)
         end
      end
   end
end
